<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 行内元素有哪些？块级元素有哪些？ 空(void)元素有那些？ -->
* 行内元素有：a b span img input select strong；
* 块级元素有：div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p；
空元素，即没有内容的HTML元素。空元素是在开始标签中关闭的，也就是空元素没有闭合标签：
* 常见的有：、<hr>、<img>、<input>、<link>、<meta>；
* 鲜见的有：<area>、<base>、<col>、<colgroup>、<command>、<embed>、<keygen>、<param>、<source>、<track>、<wbr>。


    <!-- css3的新增伪类？ -->
    p:first-of-type 选择属于其父元素的首个 <p> 元素的每个 <p> 元素。
        p:last-of-type  选择属于其父元素的最后 <p> 元素的每个 <p> 元素。
        p:only-of-type  选择属于其父元素唯一的 <p> 元素的每个 <p> 元素。
        p:only-child    选择属于其父元素的唯一子元素的每个 <p> 元素。
        p:nth-child(2)  选择属于其父元素的第二个子元素的每个 <p> 元素。
        :enabled、:disabled 控制表单控件的禁用状态。
        :checked，单选框或复选框被选中。


        <!-- css3有哪些新特性？？ -->
1. CSS3实现圆角（border-radius），阴影（box-shadow），边框图片border-image
2. 对文字加特效（text-shadow、），强制文本换行（word-wrap），线性渐变（linear-gradient）
3.旋转,缩放,定位,倾斜：transform:rotate(90deg) scale(0.85,0.90) translate(0px,-30px) skew(-9deg,0deg);
4. 增加了更多的CSS选择器、多背景、rgba()；
5. 在CSS3中唯一引入的伪元素是 ::selection ；
6. 媒体查询(@media)，多栏布局（flex）

<!-- 行内元素和块级元素的区别 -->
1）行内元素
* 设置宽高无效；
* 可以设置水平方向的margin和padding属性，不能设置垂直方向的padding和margin；
* 不会自动换行；
（2）块级元素
* 可以设置宽高；
* 设置margin和padding都有效；
* 可以自动换行；
* 多个块状，默认排列从上到下

<!-- display的block、inline和inline-block的区别 -->
（1）block： 会独占一行，多个元素会另起一行，可以设置width、height、margin和padding属性；
（2）inline： 元素不会独占一行，设置width、height属性无效。但可以设置水平方向的margin和padding属性，不能设置垂直方向的padding和margin；
（3）inline-block： 将对象设置为inline对象，但对象的内容作为block对象呈现，之后的内联对象会被排列在同一行内


<!-- 列出position和display的值？有什么作用？？ -->
     display 的值的作用：
1.block          像块类型元素一样显示
2.inline          像行内元素类型一样显示。
3.inline-block 整体行内元素一样显示（不换行），但其内容像块类型元素一样显示（可以设置宽高）
4.list-item      像块类型元素一样显示，并添加样式列表标记。
     position 的值的定位区别：
1.absolute 生成绝对定位的元素，相对于第一个已经定位的父元素进行定位
2.fixed 生成固定定位的元素，相对于浏览器窗口进行定位（老IE不支持）。
3.relative 生成相对定位的元素，相对于自己在普通流中的位置进行定位。
4.static 默认值。
5.inherit 规定从父元素继承 position 属性的值


<!-- HTML语义化的理解？？ -->
HTML语义化就是页面去掉样式或者加载失败的时候能够让页面呈现出清晰的结构。HTML5新增了好多标签，例如：header、footer、nav、menu、section、article等等，我们单单从字面上理解，就知道标签的含义。在写页面的时候，我们可以直接引用这些标签，不需要再用没有任何含义的div标签了，对于机器可以识别，对于开发人员，很容易明白，这就是HTML语义化。
语义化好处：
1）为了在没有CSS的情况下，页面也能呈现出很好地内容结构、代码结构
2）用户体验：例如title、alt用于解释名词
3）有利于SEO：利于被搜索引擎收录，更便于搜索引擎的爬虫程序来识别
4）方便其他设备解析（如屏幕阅读器、盲人阅读器、移动设备）以意义的方式来渲染网页
5）便于项目的开发及维护，使HTML代码更具有可读性

<!-- HTML5新增： -->
（1）新增语义化标签：nav、header、footer、aside、section、article
（2）音频、视频标签：audio、video
（3）数据存储：localStorage、sessionStorage
（4）canvas（画布）、Geolocation（地理定位）、websocket（通信协议）
（5）input标签新增属性：placeholder、autocomplete、autofocus、required
（6）history API：go、forward、back、pushstate
HTML5移除的元素有：
* 纯表现的元素：basefont，big，center，font, s，strike，tt，u;
* 对可用性产生负面影响的元素：frame，frameset，noframes


<!-- 常见的浏览器兼容性问题及解决方法？ -->
1、不同浏览器的标签默认的外补丁( margin )和内补丁(padding)不同
解决方案： css 里增加通配符 * { margin: 0; padding: 0; }
2、IE6双边距问题；在 IE6中设置了float , 同时又设置margin , 就会出现边距问题
解决方案：设置display:inline;
3、当标签的高度设置小于10px，在IE6、IE7中会超出自己设置的高度
解决方案：超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度
4、图片默认有间距
解决方案：使用float 为img 布局
5、IE9一下浏览器不能使用opacity
解决方案：opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);
6、边距重叠问题；当相邻两个元素都设置了margin 边距时，margin 将取最大值，舍弃最小值；
解决方案：为了不让边重叠，可以给子元素增加一个父级元素，并设置父级元素为overflow:hidden；
7、cursor:hand 显示手型在safari 上不支持
解决方案：统一使用 cursor:pointer
8、两个块级元素，父元素设置了overflow:auto；子元素设置了position:relative ;且高度大于父元素，在IE6、IE7会被隐藏而不是溢出；
解决方案：父级元素设置position:relative



<!-- Cookie、session和localStorage、以及sessionStorage之间的区别 -->
共同点：都是保存在浏览器端、且同源的
区别： https://www.cnblogs.com/zr123/p/8086525.html
1、存储路径：cookie数据始终在同源的http请求中携带（即使不需要），即cookie在浏览器和服务器间来回传递，而sessionStorage和localStorage不会自动把数据发送给服务器，仅在本地保存。cookie数据还有路径（path）的概念，可以限制cookie只属于某个路径下
2、存储大小限制也不同，cookie数据不能超过4K，同时因为每次http请求都会携带cookie、所以cookie只适合保存很小的数据，如会话标识。sessionStorage和localStorage虽然也有存储大小的限制，但比cookie大得多，可以达到5M或更大
3、数据有效期不同，sessionStorage：仅在当前浏览器窗口关闭之前有效；localStorage：始终有效，窗口或浏览器关闭也一直保存，因此用作持久数据；cookie：只在设置的cookie过期时间之前有效，即使窗口关闭或浏览器关闭
4、作用域不同，sessionStorage不在不同的浏览器窗口中共享，即使是同一个页面；localstorage在所有同源窗口中都是共享的；cookie也是在所有同源窗口中都是共享的


<!-- foreach和map的区别 -->
1. forEach()返回值是undefined，不可以链式调用。
2. map()返回一个新数组，原数组不会改变。
3. 没有办法终止或者跳出forEach()循环，除非抛出异常，所以想执行一个数组是否满足什么条件，返回布尔值，可以用一般的for循环实现，或者用Array.every()或者Array.some();
4. $.each()方法规定为每个匹配元素规定运行的函数，可以返回 false 可用于及早停止循环。


<!-- promise的概念和作用 -->
Promise 是异步编程的一种解决方案，解决回调地狱的问题，有了Promise 我们就无需嵌套！
（1）Promise的实例有三个状态:
* Pending（进行中）
* Resolved（已完成）
* Rejected（已拒绝）
    当把一件事情交给promise时，它的状态就是Pending，任务完成了状态就变成了Resolved、没有完成失败了就变成了Rejected。
（2）Promise的实例有两个过程：
* pending -> fulfilled : Resolved（已完成）
* pending -> rejected：Rejected（已拒绝）
    需要注意：一旦从进行状态变成为其他状态就永远不能更改状态了。
特点：
* 将异步操作以同步操作的流程表达出来，避免了层层嵌套的回调函数。流程更加清晰，代码更加优雅。
* Promise对象提供统一的接口，使得控制异步操作更加容易。
缺点：
* 无法取消Promise，一旦新建它就会立即执行，无法中途取消。
* 如果不设置回调函数，Promise内部抛出的错误，不会反应到外部。
* 当处于pending状态时，无法得知目前进展到哪一个阶段（刚刚开始还是即将完成）


<!-- call apply bind区别?? -->
call、bind、apply 都是 JavaScript 中用于改变（即 this 指向）的方法
call() 和apply()的第一个参数相同，就是指定的对象。这个对象就是该函数的执行上下文-即 this 指向。
call()和apply()的区别就在于，两者之间的参数。
call()在第一个参数之后的  后续所有参数就是传入该函数的值，参数是一个一个的传递。apply() 只有两个参数，第一个是对象，第二个是数组，这个数组就是该函数的参数。
bind() 方法和前两者不同在于： bind() 方法会返回执行上下文被改变的函数而不会立即执行，而前两者是直接执行该函数。他的参数和call()相同。


call 和 apply 的作用是一样的，都是用来调用函数并且改变函数内部的 this 指向。
区别在于传参的方式不同，call 的参数是一个一个传递的，而 apply 的参数是以数组的形式传递的。
bind 方法不会立即执行函数，而是返回一个新的函数，这个新的函数的 this 值被绑定到了指定的对象，调用时也可以传入参数。同时使用 bind 方法可以实现柯里化，即将函数转化为接收部分参数的函数
fn.call(obj, 1, 2); 
fn.apply(obj, [1, 2]);
————————————————
不同点：bind是创建一个新的函数，而call和aplay是用来调用函数；call和apply作用一样，只不过call为函数提供的参数是一个个地罗列出来，而apply为函数提供的参数是一个数组
————————————————
this指向与三者的关系
**在浏览器里，在全局范围内this 指向window对象；
**在函数中，this永远指向最后调用他的那个对象；
**构造函数中，this指向new出来的那个新的对象；
**call、apply、bind中的this被强绑定在指定的那个对象上；
**箭头函数中this比较特殊,箭头函数this为父作用域的this，不是调用时的this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来；
**apply、call、bind都是js给函数内置的一些API，调用他们可以为函数指定this的执行,同时也可以传参



<!-- 深拷贝和浅拷贝区别： -->
       https://www.jianshu.com/p/1c142ec2ca45
浅拷贝只是复制了对象的引用地址，两个对象指向同一个内存地址，所以修改其中任意的值，另一个值都会随之变化，这就是浅拷贝（例：assign()）
深拷贝是将对象及值复制过来，两个对象修改其中任意的值另一个值不会改变，这就是深拷贝（例：JSON.parse()和JSON.stringify()，但是此方法无法复制函数类型）
当你需要深拷贝对象中的方法时是可以用lodash.js(提高JS原生方法性能的JS库)中的cloneDeep()方法
————————————————
   如何区分深拷贝与浅拷贝，简单点来说，就是假设B复制了A，当修改A时，看B是否会发生变化，如果B也跟着变了，说明这是浅拷贝，拿人手短，如果B没变，那就是深拷贝
    1. 如果是基本数据类型，名字和值都会储存在栈内存中
    2. 如果是引用数据类型，名字存在栈内存中，值存在堆内存中，但是栈内存会提供一个引用的地址指向堆内存中的值
浅拷贝：
1）Object.assign方法
   var obj = {
      a: 1,
      b: 2
   }
   var obj1 = Object.assign(obj);
   obj1.a = 3;
   console.log(obj.a) // 3
2）直接用=赋值
   let a=[0,1,2,3,4],
       b=a;
   console.log(a===b);
   a[0]=1;
   console.log(a,b);
————————————————
深拷贝：
1）通过JSON对象来实现深拷贝
  function deepClone2(obj) {
    var _obj = JSON.stringify(obj),
      objClone = JSON.parse(_obj);
    return objClone;
   }
缺点： 无法实现对对象中方法的深拷贝，会显示为undefined
2）通过jQuery的extend方法实现深拷贝
   var array = [1,2,3,4];
   var newArray = $.extend(true,[],array); // true为深拷贝，false为浅拷贝
3）lodash函数库实现深拷贝
   let result = _.cloneDeep(test)
3）手动实现深拷贝
   let obj1 = {
     a: 1,
     b: 2
    }
  let obj2 = {
     a: obj1.a,
     b: obj1.b
   }
   obj2.a = 3;
   alert(obj1.a); // 1
   alert(obj2.a); // 3


   <!-- 谈谈this的理解？ -->
   1.在全局作用域下直接调用函数，this指向window
   2.this 总是指向函数的直接调用者--哪个对象调用 就指向哪个对象
   3.如果有 new 关键字，this 指向 new 出来的实例对象（使用 new 实例化对象，在构造函数中的this指向实例化对象）
   4.在事件中，this 指向触发这个事件的对象
   5.IE 下 attachEvent 中的 this 总是指向全局对象 Window
   
   * 如何改变this的指向？？
   call、apply、bind方法
   
   this 指向分为两种情况，一种是普通函数中使用的 this，另外一种是箭头函数中的 this
   普通函数：this 指向调用者
   箭头函数：这里就不用看谁是调用者了，而是看它定义时所在的环境（作用域）。箭头函数本身不存在 this，所以它的 this 指向上一层作用域所在的对象


   <!-- JavaScript中如何检测变量类型?js判断数组的方法及对比 -->
1.typeof 运算符    2.instanceof 运算符   3.Object.prototype.toString.call() 方法   4.constructor 属性
typeof 运算符：
let num = 123; 
console.log(typeof num); // "number"
缺点：就是对于数组和 null 对象，它都返回 “object”，因此不能很好地识别出数组和 null 类型
————————————————
instanceof 运算符
let arr = [1, 2, 3]; 
console.log(arr instanceof Array); // true
————————————————
Object.prototype.toString.call() 方法 💙💙💙
let num = 123; 
console.log(Object.prototype.toString.call(num)); // "[object Number]"
方法是一个很强大的方法，它可以识别出所有的数据类型，并且返回类型的字符串标识，如 “[object Number]”、“[object String]”、“[object Array]” 等。因此使用该方法可以很好地判断出所有数据类型
————————————————
constructor 属性
每个 JavaScript 对象都有一个 constructor 属性，表示该对象的构造函数。例如：
let arr = [1, 2, 3];
console.log(arr.constructor === Array); // true
缺点：就是对于基本数据类型（如数字、字符串），它们是没有 constructor 属性的，因此不能很好地识别出基本数据类型
总结：
   在实际开发中，我们可以根据需要选择不同的方法来判断变量的类型，如果需要识别所有的数据类型，则可以使用 Object.prototype.toString.call() 方法；
***比较：主要有三个：Object.prototype.toString.call() 、 instanceof 以及 Array.isArray()，对比如下：
* Object.prototype.toString.call()
    * 优点：这种方法对于所有基本的数据类型都能进行判断，即使是 null 和 undefined 。
    * 缺点：不能精准判断自定义对象，对于自定义对象只会返回[object Object]
* instanceOf
    * 优点：instanceof 可以弥补 Object.prototype.toString.call()不能判断自定义实例化对象的缺点。
    * 缺点： instanceof 只能用来判断对象类型，原始类型不可以。并且所有对象类型 instanceof Object 都是 true，且不同于其他两种方法的是它不能检测出 iframes。
* Array.isArray()
    * 优点：当检测 Array 实例时，Array.isArray 优于 instanceof ，因为 Array.isArray 可以检测出 iframes
    * 缺点：只能判别数组


    <!-- js去除字符串空格？？ -->
（1）replace正则匹配方法
　　去除字符串内所有的空格：str = str.replace(/\s*/g,"");
　　去除字符串内两头的空格：str = str.replace(/^\s*|\s*$/g,"");
　　去除字符串内左侧的空格：str = str.replace(/^\s*/,"");
　　去除字符串内右侧的空格：str = str.replace(/(\s*$)/g,"");
var str = " 6 6 ";
var str_1 = str.replace(/\s*/g,"");
console.log(str_1); //66
（2）trim()方法
str.trim()方法
var str = " 6 6 ";
var str_1 = str.trim();
console.log(str_1); //6 6//输出左右侧均无空格
　　单独去除左侧空格则使用 str.trimLeft();   //var str_1 = str.trimLeft();
　　单独去除右侧空格则使用 str.trimRight();  //var str_1 = str.trimRight();


<!-- new操作符具体干了什么呢? -->
1) 创建一个空对象，并且 this 变量引用该对象，同时还继承了该函数的原型。
2) 属性和方法被加入到 this 引用的对象中。
3) 新创建的对象由 this 所引用，并且最后隐式的返回 this


<!-- webpack 的运行流程是一个串行的过程，它的工作流程就是将各个插件串联起来。 -->
命令行执行npx webpack打包命令开始
1.初始化编译参数:从配置文件和shell命令中读取与合并参数
2.开始编译:根据上一步得到的参数初始化Compiler对象，加载所有配置的Plugin，执行对象的 run 方法开始执行编译。
3.确定入口:根据配置中的 entry 找出所有的入口文件
4.编译模块:从入口文件触发，调用所有配置的Loader对模块进行翻译，再找出该模块依赖的模块，然后递归本步骤直到所有入口依赖的文件都进行翻译。
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后，得到了每个模块被翻译后的最终内容以及它们之间的依赖关系图。
6.输出资源：根据依赖关系图，组装成一个个包含多个模块的Chunk，再把每个Chunk转化成一个单独的文件加入到输出列表，根据配置确定输出的路径和文件名，输出。


<!-- get和post的请求区别 -->
（1）使用Get请求时,参数在URL中显示,而使用Post请求,则不会显示出来；
（2）Post传输的数据量大，可以达到2M，而Get方法由于受到URL长度的限制,只能传递大约1024字节.
（3）Get请求请求需注意缓存问题,Post请求不需担心这个问题；
（4）Post请求必须设置Content-Type值为application/x-form-www-urlencoded；
（5）发送请求时,因为Get请求的参数都在url里,所以send函数发送的参数为null,而Post请求在使用send方法时,却需赋予其参数；
（6）GET方式请求的数据会被浏览器缓存起来，因此其他人就可以从浏览器的历史记录中读取到这些数据



<!-- 对webpack的理解 -->
webpack是一个用于现代JS应用程序的静态模块打包工具。当webpack处理应用程序时，会在内部构建一个依赖图，此依赖图对应映射到项目所需的每个模块（不再局限JS文件），并生成一个或者多个bundle
webpack的作用
* 编译代码能力：提高效率，解决浏览器兼容问题；
* 模块整合能力：提高性能，可维护性，解决浏览器频繁请求文件的问题；
* 万物皆可模块能力：项目维护性增强，支持不同种类的前端模块类型，统一的模块化方案，所有资源文件的加载都可以通过代码控制。
Webpack的构建流程
webpack的运行流程室一个串行的过程，它的工作流程是将各个插件串联起来，在运行过程中会广播事件，插件只需要监听它所关心的事件，就能加入到这条webpack机制中，去改变webpack的运作，使整个系统扩展性良好。
webpack从启动到结束会依次执行以下流程：
  **初始化参数：从配置文件和Shell语句中读取与合并参数，得出最终的参数；
  **开始编译：用上一步得到的参数初始化Compiler对象，加载所有配置的插件，执行对象的run方法开始执行编译；
  **确定入口：根据配置中的entry找出所有的入口文件；
  **编译模块：从入口文件出发，调用所有配置的Loader对模块进行翻译，再找出该模块依赖的模块，再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理；
  **完成模块编译：再经过第4步使用Loader翻译完所有模块后，得到了每个模块被翻译后的最终内容以及它们之间的依赖关系；
  **输出资源：根据入口和模块之间的依赖关系，组装成一个个包含多个模块的Chunk，再把每个Chunk转换成一个单独的文件加入到输出列表，这步是可以修改输出内容的最后机  会；
  **输出完成：在确定好输出内容后，根据配置确定输出的路径和⽂件名，把⽂件内容写⼊到⽂件系统
webpack热更新
热更新（HMR）全程Hot Module Replacement，可以理解为模块热替换，指在应用程序运行的过程中，替换、添加、删除模块，而无需重新刷新整个应用。
例如在运行过程中修改了某个模块，通过自动刷新会导致整个应用的整体刷新，那页面中的状态信息都会丢失；如果使用的是HMR，就可以实现只将修改的模块实时替换至应用中，不必完全刷新应用。
webpack 优化
1、JS代码压缩2、CSS代码压缩3、HTML文件压缩4、HTML文件压缩5、文件大小压缩6、Tree Shaking7、代码分离


<!-- loader和plugin的区别 -->
1，不同的作用：
  Loader 直译为"加载器"。
  Webpack 将⼀切⽂件视为模块，但是 webpack原⽣是只能解析 js⽂件。
  如果想将其他⽂件也打包的话，就会⽤到loader 。
  所以 Loader 的作⽤是让 webpack 拥有了加载和解析 ⾮ JavaScript⽂件的能⼒。
比如：
* 加载和解析css文件--就会用到 ‘MiniCssExtractPlugin.loader’
     //需要在webpack.config.js文件中引入mini-css-extract-pluginconst
      MiniCssExtractPlugin = require('mini-css-extract-plugin')
    //在module.rules模块中配置，描述对于什么类型的文件（test），使用什么加载器(loader)和参数(option)
lugin 直译为"插件"。
Plugin 可以扩展 webpack 的功能，让 webpack具有更多的灵活性。
在 Webpack 运⾏的⽣命周期中会⼴播出许多事件
Plugin 可以监听这些事件，在合适的时机通过 Webpack 提供的API 改变输出结果。
比如：
* 将指定html文件作为模板html然后打包--就会用到 'html-webpack-plugin'
   //需要在webpack.config.js文件中引入html-webpack-plugin
   const HtmlWebpackPlugin = require('html-webpack-plugin')
2. 不同的用法：
   Loader 在 module.rules 中配置，也就是说他作为模块的解析规则而存在。
   Plugin在 plugins 中单独配置。
   类型为数组，每⼀项是⼀个 plugin的 实例，参数都通过构造函数传⼊
3 运行时机
    * loader 运行在打包文件之前
    * plugins 在整个编译周期都起作用
4. 有哪些常⻅的Loader？
  file-loader：把⽂件输出到⼀个⽂件夹中，在代码中通过相对 URL去引⽤输出的⽂件
  url-loader：和 file-loader 类似，但是能在⽂件很⼩的情况下以base64 的⽅式把⽂件内容注⼊到代码中去
  source-map-loader：加载额外的 Source Map ⽂件，以⽅便断点调试
  image-loader：加载并且压缩图⽚⽂件
  babel-loader：把 ES6 转换成 ES5
  css-loader：加载 CSS，⽀持模块化、压缩、⽂件导⼊等特性
  style-loader：把 CSS 代码注⼊到 JavaScript 中，通过 DOM 操作去加载 CSS。
  eslint-loader：通过 ESLint 检查 JavaScript 代码
  注意：在 Webpack 中，loader 的执行顺序是从右向左执行的。因为webpack 选择了 compose 这样的函数式编程方式，这种方式的表达式执行是从右向左的
4. 有哪些常⻅的Plugin？
  define-plugin：定义环境变量
  html-webpack-plugin：简化 html⽂件创建
  uglifyjs-webpack-plugin：通过 UglifyES 压缩 ES6 代码
  webpack-parallel-uglify-plugin: 多核压缩，提⾼压缩速度
  webpack-bundle-analyzer: 可视化 webpack 输出⽂件的体积
  mini-css-extract-plugin: CSS 提取到单独的⽂件中，⽀持按需加载


  <!-- webpack的工作原理 -->
  entry： 一个可执行模块或库的入口文件。
  chunk ：多个文件组成的一个代码块，例如把一个可执行模块和它所有依赖的模块组合和一个 chunk 这体现了webpack的打包机制。
  loader ：文件转换器，例如把es6转换为es5，scss转换为css。
  plugin ：插件，用于扩展webpack的功能，在webpack构建生命周期的节点上加入扩展hook为webpack加入功能。
  2.webpack构建流程
  从启动webpack构建到输出结果经历了一系列过程，它们是：
  2.1 解析webpack配置参数，合并从shell传入和webpack.config.js文件里配置的参数，生产最后的配置结果。
  2.2 注册所有配置的插件，好让插件监听webpack构建生命周期的事件节点，以做出对应的反应。
  2.3 从配置的entry入口文件开始解析文件构建AST语法树，找出每个文件所依赖的文件，递归下去。
  2.4 在解析文件递归的过程中根据文件类型和loader配置找出合适的loader用来对文件进行转换。
  2.5 递归完后得到每个文件的最终结果，根据entry配置生成代码块chunk。
  2.6 输出所有chunk到文件系统。






</body>
</html>
<script>

    
</script>